package com.bestcem.xm.cjm.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bestcem.xm.cjm.controller.vo.ClientJourneyVo;
import com.bestcem.xm.cjm.entity.*;
import com.bestcem.xm.cjm.enums.CjmRowsTTypeEnum;
import com.bestcem.xm.cjm.enums.FileInfoFTypeEnum;
import com.bestcem.xm.cjm.grpc.client.UserGrpcClient;
import com.bestcem.xm.cjm.grpc.client.dto.UserDto;
import com.bestcem.xm.cjm.mapper.*;
import com.bestcem.xm.cjm.service.CjmClientjourneyService;
import com.bestcem.xm.common.core.domain.web.XmResultJson;
import com.bestcem.xm.common.core.exception.BusinessException;
import com.bestcem.xm.common.core.oss.enums.OssPathEnum;
import com.bestcem.xm.component.mybatis.service.impl.XmServiceImpl;
import com.bestcem.xm.component.security.context.SecurityContextHolder;
import com.bestcem.xm.componet.filestorage.service.StorageService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static com.bestcem.xm.cjm.enums.CjmClientJourneysEnum.CLIENTJOURNEY_STATUS_EDITING;
import static com.bestcem.xm.cjm.enums.CjmClientJourneysEnum.CLIENTJOURNEY_STATUS_SAVED;
import static com.bestcem.xm.cjm.util.CjmConstant.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class CjmClientjourneyServiceImpl extends XmServiceImpl<CjmClientjourneyMapper, CjmClientjourney> implements CjmClientjourneyService {

    private @NonNull CjmRowsMapper cjmRowsMapper;
    private @NonNull CjmColumnsMapper cjmColumnsMapper;
    private @NonNull CjmUserclientjourneyMapper userclientjourneyMapper;
    private @NonNull CjmPackageMapper cjmPackageMapper;
    private @NonNull UploadFileInfoMapper uploadFileInfoMapper;
    private @NonNull UploadFileMapMapper uploadFileMapMapper;

    private @NonNull UserGrpcClient userGrpcClient;
    //private @NonNull OssService ossService;
    private @NonNull StorageService storageService;

    private static final String ROOT_FILE_PATH = System.getProperty("user.dir");

    @Override
    public JSONObject postClientJourneys(JSONObject params) {
        params.put("status", CLIENTJOURNEY_STATUS_EDITING.getValue());
        String cjm_id = createClientJourney(params);
        params.put("status", CLIENTJOURNEY_STATUS_SAVED.getValue());
        params.put("parent_id", cjm_id);
        String cjm_id_publish = createClientJourney(params);
        //更新初始化数据到编辑数据
        updateClientJourney(cjm_id, createCjmData(cjm_id, params.getString("orgID")));
        //更新初始化数据到发布数据
        updateClientJourney(cjm_id_publish, createCjmData(cjm_id_publish, params.getString("orgID")));
        //创建用户文件夹数据
        String package_id = (String) params.getOrDefault("package_id", null);
        JSONObject userClientJourney = new JSONObject();
        userClientJourney.put("user_id", params.getString("user_id"));
        userClientJourney.put("clientjourney_id", cjm_id_publish);
        userClientJourney.put("own_id", params.getString("user_id"));
        userClientJourney.put("package_id", package_id);
        createUserClientJourney(userClientJourney);
        JSONObject ret = new JSONObject();
        ret.put("id", cjm_id_publish);
        return ret;
    }

    @Override
    public JSONObject deleteClientJourneyByid(String id) {
        CjmClientjourney clientjourney = baseMapper.selectById(id);
        if (ObjectUtil.isEmpty(clientjourney)) {
            throw new BusinessException("ClientJourney[id={" + id + "}] not found");
        }
        Integer superRole = SecurityContextHolder.getToken().getSuperRole();
        String userId = SecurityContextHolder.getUserId();
        if ((superRole == null || superRole == 0) && !userId.equals(clientjourney.getUserId())) {
            throw new BusinessException("PermissionDeny");
        }
        String cjm_edit = clientjourney.getParentId();
        List<String> delete_list = new ArrayList<>();
        delete_list.add(id);
        if (StrUtil.isNotBlank(cjm_edit)) {
            delete_list.add(cjm_edit);
        }
        return deleteClientJourney(delete_list);
    }

    @Override
    public JSONObject putClientJourneys(String id, JSONObject params) {
        CjmClientjourney clientjourney = baseMapper.selectById(id);
        if (ObjectUtil.isEmpty(clientjourney)) {
            throw new BusinessException("ClientJourney[id={" + id + "}] not found");
        }
        Integer superRole = SecurityContextHolder.getToken().getSuperRole();
        String userId = SecurityContextHolder.getUserId();
        if (superRole != 1 && !userId.equals(clientjourney.getUserId())) {
            throw new BusinessException("PermissionDeny");
        }
        String cjm_edit = clientjourney.getParentId();
        CjmClientjourney clientjourneyParent = baseMapper.selectById(cjm_edit);
        if (ObjectUtil.isNotEmpty(params.get("name"))) {
            clientjourney.setName(params.getString("name"));
            clientjourneyParent.setName(params.getString("name"));
        }
        if (ObjectUtil.isNotEmpty(params.get("display_name"))) {
            clientjourney.setDisplayName(params.getString("display_name"));
            clientjourneyParent.setDisplayName(params.getString("display_name"));
        }
        if (ObjectUtil.isNotEmpty(params.get("description"))) {
            clientjourney.setDescription(params.getString("description"));
            clientjourneyParent.setDescription(params.getString("description"));
        }
        baseMapper.updateById(clientjourney);
        baseMapper.updateById(clientjourneyParent);
        JSONObject ret = new JSONObject();
        ret.put("id", id);
        return ret;
    }

    @Override
    public JSONObject putUserClientJourneys(String id, JSONObject params) {
        CjmUserclientjourney userclientjourney = userclientjourneyMapper.selectById(id);
        if (ObjectUtil.isEmpty(userclientjourney)) {
            throw new BusinessException("userclientjourney[id={" + id + "}] not found");
        }
        if (ObjectUtil.isNotEmpty(params)) {
            updateUserClientJourney(id, params);
        }
        JSONObject ret = new JSONObject();
        ret.put("id", id);
        return ret;
    }

    @Override
    public List<ClientJourneyVo> getPublishClientJourney(List<CjmClientjourney> list, String uid) {
        if (ObjectUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<ClientJourneyVo> ret = new ArrayList<>();
        list.forEach(it -> ret.add(cjmToUserFrontv2(it, uid)));
        return ret;
    }

    @Override
    public ClientJourneyVo cjmToUserFrontv2(CjmClientjourney cjm, String uid) {
        ClientJourneyVo clientJourneyVo = new ClientJourneyVo();
        List<CjmUserclientjourney> user_cjm_list = userclientjourneyMapper.selectList(
                Wrappers.<CjmUserclientjourney>lambdaQuery()
                        .eq(CjmUserclientjourney::getClientjourneyId, cjm.getId())
                        .eq(CjmUserclientjourney::getUserId, uid)
        );
        CjmUserclientjourney user_cjm;
        if (!ObjectUtils.isEmpty(user_cjm_list)) {
            user_cjm = user_cjm_list.get(0);
        } else {
            JSONObject userClientJourney = new JSONObject();
            userClientJourney.put("user_id", uid);
            userClientJourney.put("own_id", cjm.getUserId());
            userClientJourney.put("clientjourney_id", cjm.getId());
            userClientJourney.put("publish_dt", LocalDateTime.now().toString());
            user_cjm = createUserClientJourney(userClientJourney);
        }
        String real_name;
        if (StrUtil.equals(uid, cjm.getUserId())) {
            real_name = cjm.getName();
        } else {
            if (!ObjectUtils.isEmpty(user_cjm_list) && StrUtil.isNotBlank(user_cjm.getDisplayName())) {
                real_name = user_cjm.getDisplayName();
            } else {
                real_name = cjm.getDisplayName();
            }
        }
        UserDto user = userGrpcClient.getUser(cjm.getUserId());
        String publisher_name = ObjectUtils.isEmpty(user) ? "" : user.getName();
        if (StrUtil.isNotBlank(user_cjm.getPackageId())) {
            CjmPackage cjmPackage = cjmPackageMapper.selectById(user_cjm.getPackageId());
            clientJourneyVo.setCjmPackage(cjmPackage);
        }
        clientJourneyVo.setId(cjm.getId());
        clientJourneyVo.setUserId(cjm.getUserId());
        clientJourneyVo.setParentId(cjm.getParentId());
        clientJourneyVo.setName(cjm.getName());
        clientJourneyVo.setDisplayName(cjm.getDisplayName());
        clientJourneyVo.setRealName(real_name);
        clientJourneyVo.setDescription(cjm.getDescription());
        clientJourneyVo.setPublisherName(publisher_name);
        clientJourneyVo.setUserclientjourney(user_cjm);
        clientJourneyVo.setUpdatedDt(cjm.getUpdatedDt());
        return clientJourneyVo;
    }

    @Override
    public JSONObject clientJourneyPackageOrder(JSONObject params) {
        JSONArray data_list = params.getJSONArray("data_list");
        int update_count = 0;
        for (Object obj : data_list) {
            //JSONObject data = (JSONObject) obj; //error
            JSONObject data = JSONObject.parseObject(JSON.toJSONString(obj));
            if ("package".equals(data.getString("ttype"))) {
                cjmPackageMapper.update(null, new LambdaUpdateWrapper<CjmPackage>()
                        .eq(CjmPackage::getId, data.getString("id"))
                        .set(CjmPackage::getOrder, data.getInteger("order")));
                update_count += 1;
            } else if ("userclientjourney".equals(data.getString("ttype"))) {
                userclientjourneyMapper.update(null, new LambdaUpdateWrapper<CjmUserclientjourney>()
                        .eq(CjmUserclientjourney::getId, data.getString("id"))
                        .set(CjmUserclientjourney::getOrder, data.getInteger("order"))
                        .set(CjmUserclientjourney::getPackageId, data.getOrDefault("package_id", null)));
                update_count += 1;
            }
        }
        JSONObject ret = new JSONObject();
        ret.put("update_count", update_count);
        return ret;
    }

    @Override
    public Object deleteClientJourneys(JSONObject baseParams, JSONObject params, Integer superRole, String userId) {
        CjmClientjourney query = baseParams.toJavaObject(CjmClientjourney.class);
        LambdaQueryWrapper<CjmClientjourney> wrapper = new LambdaQueryWrapper<>(query);
        wrapper.in(CjmClientjourney::getId, params.getJSONArray("idList"));
        List<CjmClientjourney> cjmList = baseMapper.selectList(wrapper);
        List<String> delete_list = new ArrayList<>();

        if (!ObjectUtils.isEmpty(cjmList)) {
            for (CjmClientjourney clientjourney : cjmList) {
                if ((superRole == null || superRole == 0) && !userId.equals(clientjourney.getUserId())) {
                    continue;
                }
                String parent_id = clientjourney.getParentId();
                delete_list.add(clientjourney.getId());
                if (StrUtil.isNotBlank(parent_id)) {
                    delete_list.add(parent_id);
                }
            }
        }
        return deleteClientJourney(delete_list);
    }

    @Override
    public JSONObject putClientJourneyEdit(String id, JSONObject params) {
        CjmClientjourney clientjourney = baseMapper.selectById(id);
        if (ObjectUtil.isEmpty(clientjourney)) {
            throw new BusinessException("CjmClientjourney[id={" + id + "}] not found");
        }
        Integer superRole = SecurityContextHolder.getToken().getSuperRole();
        String userId = SecurityContextHolder.getUserId();
        if (superRole != 1 && !userId.equals(clientjourney.getUserId())) {
            throw new BusinessException("PermissionDeny");
        }
        JSONArray new_rows = params.getJSONArray("rows_data");
        JSONArray new_columns = params.getJSONArray("columns_data");
        updateCjmData(SecurityContextHolder.getOrgId(), id, new_rows, new_columns);

        JSONObject ret = new JSONObject();
        ret.put("id", id);
        return ret;
    }

    @Override
    public JSONObject getClientJourneyEdit(String id) {
        //获取编辑版本数据
        CjmClientjourney cjm_edit = baseMapper.selectById(id);
        CjmClientjourney children = baseMapper.selectOne(
                new LambdaQueryWrapper<CjmClientjourney>().eq(CjmClientjourney::getParentId, id));
        JSONArray rows = new JSONArray();
        JSONArray.parseArray(cjm_edit.getRows()).forEach(a -> rows.add(cjmRowsMapper.selectById((Serializable) a)));
        JSONArray columns = new JSONArray();
        JSONArray.parseArray(cjm_edit.getColumns()).forEach(a -> columns.add(cjmColumnsMapper.selectById((Serializable) a)));
        JSONArray data = JSONArray.parseArray(cjm_edit.getData());

        JSONObject ret = new JSONObject();
        ret.put("id", id);
        ret.put("children_id", children.getId());
        ret.put("name", cjm_edit.getName());
        ret.put("display_name", cjm_edit.getDisplayName());
        ret.put("rows_data", rows);
        ret.put("columns_data", columns);
        ret.put("data", data);
        ret.put("description", cjm_edit.getDescription());
        ret.put("status", cjm_edit.getStatus());
        ret.put("dashboard_data", JSONObject.parseObject(cjm_edit.getDashboardData()));
        return ret;
    }

    @Override
    public JSONObject postClientJourneyEdit(String id) {
        //发布编辑数据
        CjmClientjourney clientJourney = baseMapper.selectById(id);
        if (ObjectUtil.isEmpty(clientJourney)) {
            throw new BusinessException("CjmClientjourney[id={" + id + "}] not found");
        }
        Integer superRole = SecurityContextHolder.getToken().getSuperRole();
        String userId = SecurityContextHolder.getUserId();
        if (superRole != 1 && !userId.equals(clientJourney.getUserId())) {
            throw new BusinessException("PermissionDeny");
        }
        JSONArray rows = JSONArray.parseArray(clientJourney.getRows());
        JSONArray columns = JSONArray.parseArray(clientJourney.getColumns());
        JSONArray data = JSONArray.parseArray(clientJourney.getData());
        JSONObject dashboard_data = JSONObject.parseObject(clientJourney.getDashboardData());
        CjmClientjourney cjm_publish = baseMapper.selectOne(
                new LambdaQueryWrapper<CjmClientjourney>().eq(CjmClientjourney::getParentId, id));
        if (ObjectUtil.isNotEmpty(cjm_publish)) {
            copyCjmData(cjm_publish.getId(), rows, columns, data, dashboard_data, null);
            baseMapper.update(null, new LambdaUpdateWrapper<CjmClientjourney>().eq(CjmClientjourney::getId, id)
                    .set(CjmClientjourney::getStatus, 1));
            JSONObject ret = new JSONObject();
            ret.put("id", cjm_publish.getId());
            return ret;
        } else {
            throw new BusinessException("CjmClientjourney[parentId={" + id + "}] not found");
        }
    }

    private void copyCjmData(String id, JSONArray rows, JSONArray columns, JSONArray data, JSONObject dashboard_data, String description) {
        //拷贝客户旅程数据，用于发布和复制客户旅程
        CjmClientjourney cjm = baseMapper.selectById(id);
        JSONArray old_cjm_rows = JSONArray.parseArray(cjm.getRows());
        JSONArray old_cjm_columns = JSONArray.parseArray(cjm.getColumns());
        JSONArray row_id_list = new JSONArray();
        rows.forEach(row_id -> {
            CjmRows row = cjmRowsMapper.selectById(row_id.toString());
            JSONObject params = new JSONObject();
            params.put("name", row.getName());
            params.put("hidden", row.getHidden());
            params.put("clientjourney_id", id);
            params.put("orgID", row.getOrgid());
            params.put("ttype", row.getTtype());
            row_id_list.add(createRows(params));
        });
        JSONArray column_id_list = new JSONArray();
        columns.forEach(column_id -> {
            CjmColumns column = cjmColumnsMapper.selectById((Serializable) column_id);
            JSONObject params = new JSONObject();
            params.put("name", column.getName());
            params.put("hidden", column.getHidden());
            params.put("clientjourney_id", id);
            params.put("orgID", column.getOrgid());
            column_id_list.add(createColumns(params));
        });
        for (int i = 0; i < data.size(); i++) {
            for (int j = 0, size = data.getJSONObject(i).getJSONArray("data").size(); j < size; j++) {
                data.getJSONObject(i).getJSONArray("data").getJSONObject(j).put("row_id", row_id_list.get(i + 1));
                data.getJSONObject(i).getJSONArray("data").getJSONObject(j).put("column_id", column_id_list.get(j));
            }
        }
        JSONObject update_params = new JSONObject();
        update_params.put("rows", row_id_list);
        update_params.put("columns", column_id_list);
        update_params.put("data", data);
        update_params.put("dashboard_data", dashboard_data);
        if (ObjectUtil.isNotEmpty(description)) {
            update_params.put("description", description);
        }
        updateClientJourney(id, update_params);

        //删除旧的行和列数据
        if (ObjectUtil.isNotEmpty(old_cjm_rows)) {
            cjmRowsMapper.deleteBatchIds(old_cjm_rows);
        }
        if (ObjectUtil.isNotEmpty(old_cjm_columns)) {
            cjmColumnsMapper.deleteBatchIds(old_cjm_columns);
        }
    }

    private String createClientJourney(JSONObject params) {
        CjmClientjourney clientJourney = new CjmClientjourney();
        if (ObjectUtil.isNotEmpty(params.get("orgID"))) {
            clientJourney.setOrgid(params.getString("orgID"));
        }
        if (ObjectUtil.isNotEmpty(params.get("user_id"))) {
            clientJourney.setUserId(params.getString("user_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("status"))) {
            clientJourney.setStatus(params.getInteger("status"));
        }
        if (ObjectUtil.isNotEmpty(params.get("name"))) {
            clientJourney.setName(params.getString("name"));
        }
        if (ObjectUtil.isNotEmpty(params.get("display_name"))) {
            clientJourney.setDisplayName(params.getString("display_name"));
        }
        if (ObjectUtil.isNotEmpty(params.get("description"))) {
            clientJourney.setDescription(params.getString("description"));
        }
        clientJourney.setDashboardData(((JSONObject) params.getOrDefault("dashboard_data", new JSONObject())).toJSONString());
        clientJourney.setData(((JSONArray) params.getOrDefault("data", new JSONArray())).toJSONString());
        clientJourney.setRows(((JSONArray) params.getOrDefault("rows", new JSONArray())).toJSONString());
        clientJourney.setColumns(((JSONArray) params.getOrDefault("columns", new JSONArray())).toJSONString());
        if (ObjectUtil.isNotEmpty(params.get("version"))) {
            clientJourney.setVersion(params.getInteger("version"));
        }
        if (ObjectUtil.isNotEmpty(params.get("parent_id"))) {
            clientJourney.setParentId(params.getString("parent_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("is_copy_demo"))) {
            clientJourney.setIsCopyDemo(params.getBooleanValue("is_copy_demo"));
        } else {
            clientJourney.setIsCopyDemo(Boolean.FALSE);
        }
        baseMapper.insert(clientJourney);
        return clientJourney.getId();
    }

    private JSONObject createCjmData(String id, String orgID) {
        //创建客户旅程初始数据
        List<String> row_id_list = new ArrayList<>();
        List<String> column_id_list = new ArrayList<>();
        ROWS_DATA.forEach(a -> {
            JSONObject row = new JSONObject(a);
            row.put("orgID", orgID);
            row.put("clientjourney_id", id);
            String model_row_id = createRows(row);
            row_id_list.add(model_row_id);
        });
        COLUMNS_DATA.forEach(a -> {
            JSONObject column = new JSONObject(a);
            column.put("orgID", orgID);
            column.put("clientjourney_id", id);
            String model_column_id = createColumns(column);
            column_id_list.add(model_column_id);
        });
        //List<Map<String, Object>> data = DATA_INIT;
        //for (int i = 0; i < data.size(); i++) {
        //    for (int j = 0; j < ((List<Map<String, Object>>) data.get(i).get("data")).size(); j++) {
        //        ((Map<String, Object>) ((List<?>) data.get(i).get("data")).get(j)).put("row_id", row_id_list.get(i + 1));
        //        ((Map<String, Object>) ((List<?>) data.get(i).get("data")).get(j)).put("column_id", column_id_list.get(j));
        //    }
        //
        //}
        String jsonString = JSON.toJSONString(DATA_INIT);
        //CONTACTPOINT_ICON_DATA 里面6个占位符
        //String url = "http://gt-dev.bestcem.vip/bestcem/test/rs";
        //String urlPrefix = StrUtil.removeSuffix(ossService.getCdn() + ossService.getFilePrefix(), "/");
        String urlPrefix = StrUtil.removeSuffix(storageService.getPropertiesValueBy(null, "domain") + storageService.getPropertiesValueBy(null, "base-path"), "/");
        //%s/cjm/cjm_icon/target.svg
        JSONArray data = JSONArray.parseArray(String.format(jsonString, urlPrefix, urlPrefix, urlPrefix, urlPrefix, urlPrefix, urlPrefix));
        for (int i = 0; i < data.size(); i++) {
            for (int j = 0, size = data.getJSONObject(i).getJSONArray("data").size(); j < size; j++) {
                data.getJSONObject(i).getJSONArray("data").getJSONObject(j).put("row_id", row_id_list.get(i + 1));
                data.getJSONObject(i).getJSONArray("data").getJSONObject(j).put("column_id", column_id_list.get(j));
            }
        }
        JSONObject ret = new JSONObject();
        ret.put("rows", row_id_list);
        ret.put("columns", column_id_list);
        ret.put("data", data);
        return ret;
    }

    private String createRows(JSONObject params) {
        CjmRows cjmRows = new CjmRows();
        cjmRows.setHidden((Integer) params.getOrDefault("hidden", 0));
        if (ObjectUtil.isNotEmpty(params.get("orgID"))) {
            cjmRows.setOrgid(params.getString("orgID"));
        }
        if (ObjectUtil.isNotEmpty(params.get("clientjourney_id"))) {
            cjmRows.setClientjourneyId(params.getString("clientjourney_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("name"))) {
            cjmRows.setName(params.getString("name"));
        }
        if (ObjectUtil.isNotEmpty(params.get("ttype"))) {
            cjmRows.setTtype(params.getInteger("ttype"));
        }
        cjmRowsMapper.insert(cjmRows);
        return cjmRows.getId();
    }

    private String updateRows(String id, JSONObject params) {
        CjmRows cjmRows = new CjmRows();
        cjmRows.setId(id);
        if (ObjectUtil.isNotEmpty(params.get("orgID"))) {
            cjmRows.setOrgid(params.getString("orgID"));
        }
        if (ObjectUtil.isNotEmpty(params.get("clientjourney_id"))) {
            cjmRows.setClientjourneyId(params.getString("clientjourney_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("hidden"))) {
            cjmRows.setHidden(params.getInteger("hidden"));
        }
        if (ObjectUtil.isNotEmpty(params.get("name"))) {
            cjmRows.setName(params.getString("name"));
        }
        if (ObjectUtil.isNotEmpty(params.get("ttype"))) {
            cjmRows.setTtype(params.getInteger("ttype"));
        }
        cjmRowsMapper.updateById(cjmRows);
        return id;
    }

    private String createColumns(JSONObject params) {
        CjmColumns cjmColumns = new CjmColumns();
        cjmColumns.setHidden((Integer) params.getOrDefault("hidden", 0));
        if (ObjectUtil.isNotEmpty(params.get("orgID"))) {
            cjmColumns.setOrgid(params.getString("orgID"));
        }
        if (ObjectUtil.isNotEmpty(params.get("clientjourney_id"))) {
            cjmColumns.setClientjourneyId(params.getString("clientjourney_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("name"))) {
            cjmColumns.setName(params.getString("name"));
        }
        cjmColumnsMapper.insert(cjmColumns);
        return cjmColumns.getId();
    }

    private String updateColumns(String id, JSONObject params) {
        CjmColumns cjmColumns = new CjmColumns();
        cjmColumns.setId(id);
        if (ObjectUtil.isNotEmpty(params.get("orgID"))) {
            cjmColumns.setOrgid(params.getString("orgID"));
        }
        if (ObjectUtil.isNotEmpty(params.get("clientjourney_id"))) {
            cjmColumns.setClientjourneyId(params.getString("clientjourney_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("hidden"))) {
            cjmColumns.setHidden(params.getInteger("hidden"));
        }
        if (ObjectUtil.isNotEmpty(params.get("name"))) {
            cjmColumns.setName(params.getString("name"));
        }
        cjmColumnsMapper.updateById(cjmColumns);
        return id;
    }

    private void updateClientJourney(String id, JSONObject params) {
        CjmClientjourney clientjourney = new CjmClientjourney();
        clientjourney.setId(id);
        if (ObjectUtil.isNotEmpty(params.get("orgID"))) {
            clientjourney.setOrgid(params.getString("orgID"));
        }
        if (ObjectUtil.isNotEmpty(params.get("user_id"))) {
            throw new BusinessException("update clientjourney.user_id is not allowed");
        }
        if (ObjectUtil.isNotEmpty(params.get("name"))) {
            clientjourney.setName(params.getString("name"));
        }
        if (ObjectUtil.isNotEmpty(params.get("display_name"))) {
            clientjourney.setDisplayName(params.getString("display_name"));
        }
        if (ObjectUtil.isNotEmpty(params.get("description"))) {
            clientjourney.setDescription(params.getString("description"));
        }
        if (ObjectUtil.isNotEmpty(params.get("dashboard_data"))) {
            clientjourney.setDashboardData(params.getString("dashboard_data"));
        }
        if (ObjectUtil.isNotEmpty(params.get("data"))) {
            clientjourney.setData(params.getJSONArray("data").toJSONString());
        }
        if (ObjectUtil.isNotEmpty(params.get("rows"))) {
            clientjourney.setRows(params.getJSONArray("rows").toJSONString());
        }
        if (ObjectUtil.isNotEmpty(params.get("columns"))) {
            clientjourney.setColumns(params.getJSONArray("columns").toJSONString());
        }
        if (ObjectUtil.isNotEmpty(params.get("status"))) {
            clientjourney.setStatus(params.getInteger("status"));
        }
        if (ObjectUtil.isNotEmpty(params.get("version"))) {
            clientjourney.setVersion(params.getInteger("version"));
        }
        if (ObjectUtil.isNotEmpty(params.get("parent_id"))) {
            clientjourney.setParentId(params.getString("parent_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("is_copy_demo"))) {
            clientjourney.setIsCopyDemo(params.getBooleanValue("is_copy_demo"));
        }
        baseMapper.updateById(clientjourney);
    }

    @Override
    public XmResultJson<?> bindDashboard(CjmClientjourney clientjourney, JSONObject dashboard_data) {
        JSONArray data = JSONArray.parseArray(clientjourney.getData());
        cleanSignature(data);

        JSONObject updataInfo = new JSONObject();
        updataInfo.put("data", data);
        updataInfo.put("dashboard_data", dashboard_data);
        updateClientJourney(clientjourney.getId(), updataInfo);

        JSONObject ret = new JSONObject();
        ret.put("id", clientjourney.getId());
        return XmResultJson.success(ret);
    }

    @Override
    public JSONObject putClientJourneyEditV2(String id, JSONObject params) {
        CjmClientjourney clientJourney = baseMapper.selectById(id);
        if (ObjectUtil.isEmpty(clientJourney)) {
            throw new BusinessException("CjmClientJourney[id={" + id + "}] not found");
        }
        Integer superRole = SecurityContextHolder.getToken().getSuperRole();
        String userId = SecurityContextHolder.getUserId();
        if (superRole != 1 && !userId.equals(clientJourney.getUserId())) {
            throw new BusinessException("PermissionDeny");
        }
        if (!params.containsKey("DataList")) {
            throw new BusinessException("DataList is required");
        }
        JSONArray data_list = params.getJSONArray("DataList");
        int update_count = 0;
        JSONArray cjm_data = JSONArray.parseArray(clientJourney.getData());
        List<Object> row_id_list = JSONArray.parseArray(clientJourney.getRows()).subList(1, JSONArray.parseArray(clientJourney.getRows()).size());
        JSONArray column_id_list = JSONArray.parseArray(clientJourney.getColumns());

        for (int i = 0; i < data_list.size(); i++) {
            JSONObject data_dic = data_list.getJSONObject(i);
            if (!ObjectUtil.isAllNotEmpty(data_dic.get("row_id"), data_dic.get("column_id"), data_dic.get("data"))) {
                throw new BusinessException("params lost");
            }
            if (row_id_list.contains(data_dic.get("row_id")) && column_id_list.contains(data_dic.get("column_id"))) {
                int row = row_id_list.indexOf(data_dic.get("row_id"));
                int column = column_id_list.indexOf(data_dic.get("column_id"));
                cjm_data.getJSONObject(row).getJSONArray("data").getJSONObject(column).put("data", data_dic.get("data"));
            }
            update_count += 1;
        }
        baseMapper.update(null, new LambdaUpdateWrapper<CjmClientjourney>().eq(CjmClientjourney::getId, id)
                .set(CjmClientjourney::getData, cjm_data.toJSONString()));
        JSONObject ret = new JSONObject();
        ret.put("update_count", update_count);
        return ret;
    }

    @Override
    public Object copyJourney(String id, JSONObject param) {
        //创建草稿
        param.put("status", CLIENTJOURNEY_STATUS_EDITING.getValue());
        String cjm_id_edit = createClientJourney(param);

        //创建发布
        param.put("status", CLIENTJOURNEY_STATUS_SAVED.getValue());
        param.put("parent_id", cjm_id_edit);
        String cjm_id_publish = createClientJourney(param);

        //获取被复制的发布数据
        CjmClientjourney copy_cjm_publish = baseMapper.selectById(id);
        if (ObjectUtil.isEmpty(copy_cjm_publish)) {
            XmResultJson.fail(-1, String.format("ClientJourney[id=%s] not found", id));
        }
        JSONArray publish_rows = JSONArray.parseArray(copy_cjm_publish.getRows());
        JSONArray publish_columns = JSONArray.parseArray(copy_cjm_publish.getColumns());
        JSONArray publish_data = JSONArray.parseArray(copy_cjm_publish.getData());
        String parent_id = copy_cjm_publish.getParentId();
        JSONObject publish_dashboard_data = JSONObject.parseObject(copy_cjm_publish.getDashboardData());
        String publish_description = copy_cjm_publish.getDescription();
        //复制数据
        copyCjmData(cjm_id_publish, publish_rows, publish_columns, publish_data, publish_dashboard_data, publish_description);

        //获取被复制的编辑数据
        CjmClientjourney copy_cjm_edit = baseMapper.selectById(parent_id);
        if (ObjectUtil.isEmpty(copy_cjm_edit)) {
            XmResultJson.fail(-1, String.format("ClientJourney[id=%s] not found", id));
        }
        JSONArray edit_rows = JSONArray.parseArray(copy_cjm_edit.getRows());
        JSONArray edit_columns = JSONArray.parseArray(copy_cjm_edit.getColumns());
        JSONArray edit_data = JSONArray.parseArray(copy_cjm_edit.getData());
        JSONObject edit_dashboard_data = JSONObject.parseObject(copy_cjm_edit.getDashboardData());
        String edit_description = copy_cjm_edit.getDescription();
        copyCjmData(cjm_id_edit, edit_rows, edit_columns, edit_data, edit_dashboard_data, edit_description);

        JSONObject cjm_params = new JSONObject();
        cjm_params.put("user_id", param.getString("user_id"));
        cjm_params.put("clientjourney_id", cjm_id_publish);
        cjm_params.put("own_id", param.getString("user_id"));
        if (StrUtil.isNotBlank(param.getString("package_id")) && !StrUtil.equals("null", param.getString("package_id"))) {
            cjm_params.put("package_id", param.getString("package_id"));
        }
        createUserClientJourney(cjm_params);

        JSONObject ret = new JSONObject();
        ret.put("id", cjm_id_publish);
        return ret;
    }

    @Override
    public JSONObject clientJourneyImageUpload(MultipartFile file, String projectID, boolean keep_ext, boolean image_type_icon) throws Exception {
        UploadFileInfo uploadFileInfo = new UploadFileInfo();
        String fileInfoId;
        String fileMapId;
        String fileExt = "png";
        String origin_filepath;
        JSONObject compressJson;
        JSONObject data = new JSONObject();
        String filename = file.getOriginalFilename();
        byte[] bytes = file.getBytes();
        data.put("filename", filename);
        String path = ROOT_FILE_PATH + File.separator + StrUtil.replace(OssPathEnum.TEMP_OTHERS.getPath(), "/", File.separator);
        String fileId = DigestUtils.md5Hex(file.getInputStream());
        //上传图片格式
        if (filename != null && filename.lastIndexOf(".") != -1) {
            fileExt = filename.substring(filename.lastIndexOf(".") + 1);
            fileExt = fileExt.toLowerCase();
            if (keep_ext) {
                filename = fileId + "." + fileExt;
            }
        }
        //创建查询条件对象
        LambdaQueryWrapper<UploadFileInfo> queryWrapper = Wrappers.lambdaQuery();
        //根据fileId判断图片是否上传过MD5
        queryWrapper
                .eq(UploadFileInfo::getFileId, fileId).last("limit 1");
        UploadFileInfo isExistUploadFileInfo = uploadFileInfoMapper.selectOne(queryWrapper);
        //1.插upload_fileinfo信息
        if (ObjectUtil.isEmpty(isExistUploadFileInfo)) {

            File file1 = new File(path);
            if (!file1.exists()) {
                file1.mkdirs();
            }
            File image = new File(path, filename);
            file.transferTo(image);
            //上传图片
            //origin_filepath = ossService.uploadSimpleFile2(image, filename, OssPathEnum.OTHERS.getPath(), 0, null, "", OssPathEnum.OTHERS);
            origin_filepath = storageService.upload(image, filename, OssPathEnum.OTHERS.getPath(), new Dict()).getUrl();

            uploadFileInfo.setFileId(fileId);
            uploadFileInfo.setFileSize((int) image.length());
            uploadFileInfo.setFtype(FileInfoFTypeEnum.FILEINFO_FTYPE_IMAGE.getValue());
            uploadFileInfo.setPolicy(1);
            uploadFileInfo.setUrl(origin_filepath);
            uploadFileInfoMapper.insert(uploadFileInfo);
            fileInfoId = uploadFileInfo.getId();
            // 删除临时文件
            image.delete();
        } else {
            fileInfoId = isExistUploadFileInfo.getId();
            origin_filepath = isExistUploadFileInfo.getUrl();
        }
        //2.插upload_filemap信息
        fileMapId = uploadFileMap(fileInfoId, filename, projectID);
        //图片按比例压缩为最长边200px
        InputStream in = new ByteArrayInputStream(bytes);
        BufferedImage image1 = ImageIO.read(in);
        int max_len = Math.max(image1.getWidth(), image1.getHeight());
        if (max_len > 200) {
            Image scaledInstance = image1.getScaledInstance(Double.valueOf(200).intValue(), Double.valueOf(200).intValue(), Image.SCALE_DEFAULT);
            // 5、将Image类型转换成BufferedImage对象[BufferedImage.TYPE_INT_ARGB：表示具有8位RGBA颜色成分的整数像素的图像]
            BufferedImage newImage = new BufferedImage(Double.valueOf(200).intValue(), Double.valueOf(200).intValue(), BufferedImage.TYPE_INT_RGB);
            // 一个新的图形上下文，这是这个图形上下文的副本
            Graphics g = newImage.getGraphics();
            // 绘制图片大小
            g.drawImage(scaledInstance, 0, 0, null);
            // 释放文件资源
            g.dispose();
            // 将新的图片文件写入到指定的文件夹中
            File file1 = new File(path+ filename);
            if (!file1.exists()) {
                file1.mkdirs();
            }
            File file2 = new File(path + filename);
            ImageIO.write(newImage, fileExt, file2);

            InputStream inputStream = Files.newInputStream(file2.toPath());
            MultipartFile compressFile = new MockMultipartFile(file2.getName(), inputStream);
            compressJson = compressImageUpload(compressFile, projectID, keep_ext, filename);
            data.put("compress_id", compressJson.get("compress_id"));
            data.put("compress_filepath", compressJson.get("compress_filepath"));
        } else {
            data.put("compress_id", fileMapId);
            data.put("compress_filepath", origin_filepath);
        }

        JSONObject ret = new JSONObject();
        data.put("origin_id", fileMapId);
        data.put("origin_filepath", origin_filepath);
        ret.put("file", data);
        return ret;
    }

    public String uploadFileMap(String fileId, String filename, String projectId) {
        UploadFileMap uploadFileMap = new UploadFileMap();
        uploadFileMap.setFileName(filename);
        uploadFileMap.setFileInfoId(fileId);
        uploadFileMap.setOriginFileInfoId(fileId);
        //uploadFileMap.setProjectId(projectId);
        uploadFileMap.setSysId("cjm");

        uploadFileMapMapper.insert(uploadFileMap);

        return uploadFileMap.getId();
    }

    private JSONObject compressImageUpload(MultipartFile file, String projectID, boolean keep_ext, String filename) throws Exception {
        UploadFileInfo uploadFileInfo = new UploadFileInfo();
        String fileInfoId;
        String fileMapId;
        String compress_path;
        String path = ROOT_FILE_PATH + File.separator + StrUtil.replace(OssPathEnum.TEMP_OTHERS.getPath(), "/", File.separator);
        String fileId = DigestUtils.md5Hex(file.getInputStream());
        String newFileName = null;
        //上传图片格式
        if (filename != null && filename.lastIndexOf(".") != -1) {
            String fileExt = filename.substring(filename.lastIndexOf(".") + 1);
            fileExt = fileExt.toLowerCase();
            if (keep_ext) {
                newFileName = fileId + "." + fileExt;
            }
        }
        //创建查询条件对象
        LambdaQueryWrapper<UploadFileInfo> queryWrapper = Wrappers.lambdaQuery();
        //根据fileId判断图片是否上传过MD5
        queryWrapper
                .eq(UploadFileInfo::getFileId, fileId).last("limit 1");
        UploadFileInfo isExistUploadFileInfo = uploadFileInfoMapper.selectOne(queryWrapper);
        //1.插upload_fileinfo信息
        if (ObjectUtil.isEmpty(isExistUploadFileInfo)) {

            File file1 = new File(path);
            if (!file1.exists()) {
                file1.mkdirs();
            }
            File image = new File(path, filename);
            file.transferTo(image);
            //上传图片
            //compress_path = ossService.uploadSimpleFile2(image, newFileName, OssPathEnum.OTHERS.getPath(), 0, null, "", OssPathEnum.OTHERS);
            compress_path = storageService.upload(image, newFileName, OssPathEnum.OTHERS.getPath(), new Dict()).getUrl();

            uploadFileInfo.setFileId(fileId);
            uploadFileInfo.setFileSize((int) image.length());
            uploadFileInfo.setFtype(FileInfoFTypeEnum.FILEINFO_FTYPE_IMAGE.getValue());
            uploadFileInfo.setPolicy(1);
            uploadFileInfo.setUrl(compress_path);
            uploadFileInfoMapper.insert(uploadFileInfo);
            fileInfoId = uploadFileInfo.getId();
            // 删除临时文件
            image.delete();
        } else {
            fileInfoId = isExistUploadFileInfo.getId();
            compress_path = isExistUploadFileInfo.getUrl();
        }
        //2.插upload_filemap信息
        fileMapId = uploadFileMap(fileInfoId, filename, projectID);


        JSONObject data = new JSONObject();
        data.put("compress_id", fileMapId);
        data.put("fileInfoId", fileInfoId);
        data.put("compress_filepath", compress_path);
        return data;
    }

    @Override
    public JSONArray clientJourneyImagelibUpload(MultipartFile file, String projectID, boolean keep_ext, boolean image_type_icon) throws Exception {
        UploadFileInfo uploadFileInfo = new UploadFileInfo();
        String fileInfoId;
        String fileMapId;
        String fileExt = "png";
        String origin_filepath;
        JSONObject compressJson;
        JSONObject data = new JSONObject();
        String filename = file.getOriginalFilename();
        byte[] bytes = file.getBytes();
        data.put("filename", filename.split("\\.")[0]);
        String path = ROOT_FILE_PATH + File.separator + StrUtil.replace(OssPathEnum.TEMP_OTHERS.getPath(), "/", File.separator);
        String fileId = DigestUtils.md5Hex(file.getInputStream());
        //上传图片格式
        if (filename != null && filename.lastIndexOf(".") != -1) {
            fileExt = filename.substring(filename.lastIndexOf(".") + 1);
            fileExt = fileExt.toLowerCase();
            if (keep_ext) {
                filename = fileId + "." + fileExt;
            }
        }
        //创建查询条件对象
        LambdaQueryWrapper<UploadFileInfo> queryWrapper = Wrappers.lambdaQuery();
        //根据fileId判断图片是否上传过MD5
        queryWrapper
                .eq(UploadFileInfo::getFileId, fileId).last("limit 1");
        UploadFileInfo isExistUploadFileInfo = uploadFileInfoMapper.selectOne(queryWrapper);
        //1.插upload_fileinfo信息
        if (ObjectUtil.isEmpty(isExistUploadFileInfo)) {

            File file1 = new File(path);
            if (!file1.exists()) {
                file1.mkdirs();
            }
            File image = new File(path, filename);
            file.transferTo(image);
            //上传图片
            //origin_filepath = ossService.uploadSimpleFile2(image, filename, OssPathEnum.OTHERS.getPath(), 0, null, "", OssPathEnum.OTHERS);
            origin_filepath = storageService.upload(image, filename, OssPathEnum.OTHERS.getPath(), new Dict()).getUrl();

            uploadFileInfo.setFileId(fileId);
            uploadFileInfo.setFileSize((int) image.length());
            uploadFileInfo.setFtype(FileInfoFTypeEnum.FILEINFO_FTYPE_IMAGE.getValue());
            uploadFileInfo.setPolicy(1);
            uploadFileInfo.setUrl(origin_filepath);
            uploadFileInfoMapper.insert(uploadFileInfo);
            fileInfoId = uploadFileInfo.getId();
            // 删除临时文件
            image.delete();
        } else {
            fileInfoId = isExistUploadFileInfo.getId();
            origin_filepath = isExistUploadFileInfo.getUrl();
        }
        //2.插upload_filemap信息
        fileMapId = uploadFileMap(fileInfoId, filename, projectID);
        //图片按比例压缩为最长边200px
        InputStream in = new ByteArrayInputStream(bytes);
        BufferedImage image1 = ImageIO.read(in);
        int max_len = Math.max(image1.getWidth(), image1.getHeight());
        if (max_len > 200) {
            Image scaledInstance = image1.getScaledInstance(Double.valueOf(200).intValue(), Double.valueOf(200).intValue(), Image.SCALE_DEFAULT);
            // 5、将Image类型转换成BufferedImage对象[BufferedImage.TYPE_INT_ARGB：表示具有8位RGBA颜色成分的整数像素的图像]
            BufferedImage newImage = new BufferedImage(Double.valueOf(200).intValue(), Double.valueOf(200).intValue(), BufferedImage.TYPE_INT_RGB);
            // 一个新的图形上下文，这是这个图形上下文的副本
            Graphics g = newImage.getGraphics();
            // 绘制图片大小
            g.drawImage(scaledInstance, 0, 0, null);
            // 释放文件资源
            g.dispose();
            // 将新的图片文件写入到指定的文件夹中
            File file1 = new File(path+ filename);
            if (!file1.exists()) {
                file1.mkdirs();
            }
            File file2 = new File(path + filename);
            ImageIO.write(newImage, fileExt, file2);

            InputStream inputStream = Files.newInputStream(file2.toPath());
            MultipartFile compressFile = new MockMultipartFile(file2.getName(), inputStream);
            compressJson = compressImageUpload(compressFile, projectID, keep_ext, filename);
            data.put("filemap_id", compressJson.get("compress_id"));
            data.put("imagelib_id", compressJson.get("fileInfoId"));
            data.put("file_path", compressJson.get("compress_filepath"));
        } else {
            data.put("filemap_id", fileMapId);
            data.put("imagelib_id", fileInfoId);
            data.put("file_path", origin_filepath);
        }
        JSONArray ret = new JSONArray();
        ret.add(data);
        return ret;
    }

    /**
     * 清除data中的signature
     *
     * @author chenglong.yue <chenglong.yue@idiaoyan.com>
     * @date 2023/5/12 13:52
     */
    private void cleanSignature(JSONArray data) {
        data.forEach(rowtmp -> {
            JSONObject row = (JSONObject) rowtmp;
            if (row.getIntValue("ttype") == CjmRowsTTypeEnum.ROWS_TTYPE_INDEX.getValue()) {
                JSONArray columnList = row.getJSONArray("data");
                columnList.forEach(columntmp -> {
                    JSONObject column = (JSONObject) columntmp;
                    JSONArray sigList = Optional.ofNullable(column.getJSONObject("data").getJSONArray("index")).orElse(new JSONArray());
                    sigList.forEach(sigtmp -> {
                        JSONObject sig = (JSONObject) sigtmp;
                        sig.put("chart_signature", "");
                        sig.put("dashboard_signature", "");
                    });
                });
            }
        });
    }

    private CjmUserclientjourney createUserClientJourney(JSONObject params) {
        CjmUserclientjourney userClientJourney = new CjmUserclientjourney();
        if (ObjectUtil.isNotEmpty(params.get("user_id"))) {
            userClientJourney.setUserId(params.getString("user_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("clientjourney_id"))) {
            userClientJourney.setClientjourneyId(params.getString("clientjourney_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("own_id"))) {
            userClientJourney.setOwnId(params.getString("own_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("package_id"))) {
            userClientJourney.setPackageId(params.getString("package_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("display_name"))) {
            userClientJourney.setDisplayName(params.getString("display_name"));
        }
        if (ObjectUtil.isNotEmpty(params.get("publish_dt"))) {
            userClientJourney.setPublishDt(LocalDateTimeUtil.parse(params.getString("publish_dt")));
        }
        userClientJourney.setOrder((Integer) params.getOrDefault("order", 0));
        userClientJourney.setFirstPage(params.getBooleanValue("first_page"));
        userClientJourney.setIsCopyDemo(params.getBooleanValue("is_copy_demo"));
        userclientjourneyMapper.insert(userClientJourney);
        return userClientJourney;
    }

    private JSONObject deleteClientJourney(List<String> delete_list) {
        if (ObjectUtils.isEmpty(delete_list)) {
            return new JSONObject();
        }
        JSONObject ret = new JSONObject();
        ret.put("userclientjourney_delete_count", userclientjourneyMapper.delete(new LambdaQueryWrapper<CjmUserclientjourney>().in(CjmUserclientjourney::getClientjourneyId, delete_list)));
        ret.put("column_delete_count", cjmColumnsMapper.delete(new LambdaQueryWrapper<CjmColumns>().in(CjmColumns::getClientjourneyId, delete_list)));
        ret.put("row_delete_count", cjmRowsMapper.delete(new LambdaQueryWrapper<CjmRows>().in(CjmRows::getClientjourneyId, delete_list)));
        ret.put("clientjourney_delete_count", baseMapper.deleteBatchIds(delete_list));
        return ret;
    }

    private void updateUserClientJourney(String id, JSONObject params) {
        LambdaUpdateWrapper<CjmUserclientjourney> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CjmUserclientjourney::getId, id);
        if (ObjectUtil.isNotEmpty(params.get("user_id"))) {
            updateWrapper.set(CjmUserclientjourney::getUserId, params.getString("user_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("clientjourney_id"))) {
            updateWrapper.set(CjmUserclientjourney::getClientjourneyId, params.getString("clientjourney_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("own_id"))) {
            updateWrapper.set(CjmUserclientjourney::getOwnId, params.getString("own_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("package_id"))) {
            updateWrapper.set(CjmUserclientjourney::getPackageId, params.getString("package_id"));
        }
        if (ObjectUtil.isNotEmpty(params.get("display_name"))) {
            updateWrapper.set(CjmUserclientjourney::getDisplayName, params.getString("display_name"));
        }
        if (ObjectUtil.isNotEmpty(params.get("publish_dt"))) {
            updateWrapper.set(CjmUserclientjourney::getPublishDt, LocalDateTimeUtil.parse(params.getString("publish_dt")));
        }
        updateWrapper.set(CjmUserclientjourney::getOrder, params.getOrDefault("order", 0));
        updateWrapper.set(CjmUserclientjourney::getFirstPage, params.getBooleanValue("first_page"));
        updateWrapper.set(CjmUserclientjourney::getIsCopyDemo, params.getBooleanValue("is_copy_demo"));
        userclientjourneyMapper.update(null, updateWrapper);
    }

    private void updateCjmData(String orgId, String id, JSONArray row_data, JSONArray column_data) {
        //更新客戶旅程數據
        CjmClientjourney old_cjm = baseMapper.selectById(id);
        JSONArray old_cjm_data = JSONArray.parseArray(old_cjm.getData());
        JSONArray new_row_id = new JSONArray();
        for (int i = 0; i < row_data.size(); i++) {
            JSONObject row = row_data.getJSONObject(i);
            JSONObject params = new JSONObject();
            params.put("clientjourney_id", id);
            params.put("name", row.get("name"));
            params.put("orgID", orgId);
            params.put("ttype", row.get("ttype"));
            params.put("hidden", row.get("hidden"));
            if (ObjectUtil.isEmpty(row.get("id"))) {
                new_row_id.add(createRows(params));
            } else {
                new_row_id.add(updateRows(row.getString("id"), params));
            }
        }
        JSONArray new_column_id = new JSONArray();
        for (int i = 0; i < column_data.size(); i++) {
            JSONObject column = column_data.getJSONObject(i);
            JSONObject params = new JSONObject();
            params.put("clientjourney_id", id);
            params.put("name", column.get("name"));
            params.put("orgID", orgId);
            params.put("hidden", column.get("hidden"));
            if (ObjectUtil.isEmpty(column.get("id"))) {
                new_column_id.add(createColumns(params));
            } else {
                new_column_id.add(updateColumns(column.getString("id"), params));
            }
        }
        JSONObject old_data = new JSONObject();
        old_cjm_data.forEach(i -> ((JSONObject) i).getJSONArray("data").forEach(a -> {
            JSONObject j = (JSONObject) a;
            old_data.put(j.getString("row_id") + "_" + j.getString("column_id"), j.get("data"));
        }));
        JSONArray data = new JSONArray();
        for (int i = 0; i < new_row_id.size(); i++) {
            JSONArray ele = new JSONArray();
            String row_id = new_row_id.getString(i);
            Integer row_hidden = row_data.getJSONObject(i).getInteger("hidden");
            Integer row_ttype = row_data.getJSONObject(i).getInteger("ttype");
            if (row_ttype == 0) {
                continue;
            }
            JSONObject data_row = new JSONObject();
            for (int j = 0; j < new_column_id.size(); j++) {
                JSONObject element = new JSONObject();
                Integer hidden;
                String column_id = new_column_id.getString(j);
                Integer column_hidden = column_data.getJSONObject(j).getInteger("hidden");
                if (row_hidden == 0 && column_hidden == 0) {
                    hidden = 0;
                } else {
                    hidden = 1;
                }
                if (ObjectUtil.isNotEmpty(old_data.get(row_id + "_" + column_id))) {
                    element.put("row_id", row_id);
                    element.put("column_id", column_id);
                    element.put("hidden", hidden);
                    element.put("data", old_data.get(row_id + "_" + column_id));
                } else if (row_ttype == 1) {
                    element.put("row_id", row_id);
                    element.put("column_id", column_id);
                    element.put("hidden", hidden);
                    element.put("data", CONTACTPOINT_DATA);
                } else if (row_ttype == 2) {
                    element.put("row_id", row_id);
                    element.put("column_id", column_id);
                    element.put("hidden", hidden);
                    element.put("data", initData());
                } else {
                    element.put("row_id", row_id);
                    element.put("column_id", column_id);
                    element.put("hidden", hidden);
                    element.put("data", customizeData());
                }
                ele.add(element);
            }
            data_row.put("data", ele);
            data_row.put("ttype", row_ttype);
            data_row.put("hidden", row_hidden);
            data.add(data_row);
        }
        JSONObject updataInfo = new JSONObject();
        updataInfo.put("rows", new_row_id);
        updataInfo.put("columns", new_column_id);
        updataInfo.put("data", data);
        updataInfo.put("status", 0);
        updateClientJourney(id, updataInfo);
    }
}
